<?php

namespace App\Services\Repositories\SkinRecord;

use App\Models\Panx\Activity;
use App\Models\Panx\SkinRecordBonus;
use App\Models\Store\HmSkinRecord;
use App\Models\Store\SkinRecord;
use App\Models\Store\WaxSkinRecord;


/**
 * 肤测记录发放条件检查
 *
 * Class SkinRecordRepository
 * @package App\Services\SkinRecord
 */
class SkinRecordBonusGrantCheck
{
    const DISABLE_GRANT_DEV_ACNT_IDS = [
        // makeup01 - 12 展会期间不发红包
        374, 375, 376, 377, 378, 379, 380, 381, 382, 383, 384, 385,
    ];

    /**
     * @var SkinRecord
     */
    protected $skin_record;

    public function __construct()
    {
        $this->skin_record = new SkinRecord();
    }

    protected $status = [
        'has_store_admin'              => null,
        'enough_amount'                => null,
        'activity_alive'               => null,
        
        'use_wx_pay'                   => null,
        'staff_has_wx'                 => null, // 线上出现了使用没有绑定微信的店员的情况

        'use_ali_pay'                  => null,
        'staff_has_ali_account'        => null,
        
        'all_sub_records_done'         => null,
        'staff_record_self'            => null,
        
        'skin_record_bonus_exist'      => null,
//        'staff_same_wx_bonus_exist'    => null,
        'wx_same_customer_bonus_exist' => null,
    ];

    /**
     * @test
     *
     * 肤质纪录是否满足发放红包的条件
     *
     * @param SkinRecord $skinRecord
     * @return bool
     */
    public function canGrantBonus(SkinRecord $skinRecord): bool
    {
        $can = (
            $this->canAccountGrant($skinRecord) &&

            $this->hasStoreAdmin($skinRecord) &&  // 是否选择了店员
            
            $this->hasEnoughBonusAmount() &&      // 检查奖金池余额

            $this->isActivityAlive() &&           // 检查红包活动是否有效

            $this->checkPayTypeHasRelateAccount($skinRecord) &&  // 检测店员是否有微信账号或支付宝账号

            $this->isAllSubSkinRecordsDone($skinRecord) &&       // 检测是否检测完所有的项目

            ! $this->isStoreAdminRecordSelf($skinRecord) &&      // 店员不能对自己测肤

            ! $this->isSkinRecordBonusExist($skinRecord) &&      // 同一 skin record 只发放一次，即使失败对同一 skin record 也只发一次

//            ! $this->isStoreAdminSameWxUserBonusExistToday($skinRecord) &&

            ! $this->isWxUserSameCustomerBonusExistToday($skinRecord)  // 对同一客户下的消费者，一天只有第一次成功测此消费者的店员可获取红包
        );

//        logger(['skin_record_id' => $skinRecord->id] + $this->status);

        return $can;
    }

    public function getStatus(): array
    {
        return $this->status;
    }


    /**
     * 检查奖金池 -  所有 skin_record_bonuses 之和大于等于总金额时，不再发放红包
     * @return bool
     */
    private function hasEnoughBonusAmount(): bool
    {
        $this->status['enough_amount'] = (new SkinRecordBonus)->sum('amount') < SkinRecordBonus::MAX_BONUS_AMOUNT;

        return $this->status['enough_amount'];
    }

    /**
     * 检查是否选择了店员
     *
     * @param SkinRecord $skinRecord
     * @return bool
     */
    private function hasStoreAdmin(SkinRecord $skinRecord): bool
    {
        $this->status['has_store_admin'] = (bool) $skinRecord->storeAdmin;

        return $this->status['has_store_admin'];
    }

    /**
     * 店员不能对自己测肤
     *
     * @param SkinRecord $skinRecord
     * @return bool
     */
    private function isStoreAdminRecordSelf(SkinRecord $skinRecord): bool
    {
        $this->status['staff_record_self'] = $skinRecord->storeAdmin->wechat_user_id === $skinRecord->wechat_user_id;

        return $this->status['staff_record_self']; // 店员给自己测肤无红包
    }

    /**
     * 同一 skin record 只发放一次，即使失败对同一 skin record 也只发一次
     *
     * @param SkinRecord $skinRecord
     * @return bool
     */
    private function isSkinRecordBonusExist(SkinRecord $skinRecord): bool
    {
        $this->status['skin_record_bonus_exist'] = (new SkinRecordBonus)
            ->where('skin_record_id', $skinRecord->id)
            ->exists();

        return $this->status['skin_record_bonus_exist'];
    }

    /**
     * @deprecated - 这个条件应该已经被 isWxUserSameCustomerBonusExistToday 包括了，同一客户的消费者只要有当天有一次就不会再发了
     *
     * 一个店员一天只能从同一消费者的测肤数据发放一次红包
     *
     * @param SkinRecord $skinRecord
     *
     * @return bool
     */
    private function isStoreAdminSameWxUserBonusExistToday(SkinRecord $skinRecord): bool
    {
        $today_staff_same_wx_user_rec_ids = (new SkinRecord)
            ->filterToday('created_at')
            ->where([
                'store_admin_id' => $skinRecord->store_admin_id,
                'wechat_user_id' => $skinRecord->wechat_user_id,
            ])
            ->pluck('id')
            ->all();

        $exist = $this->status['staff_same_wx_bonus_exist'] = (new SkinRecordBonus)
            ->where('bonus_status', SkinRecordBonus::BONUS_STATUS_SUCCESS) // 上次失败可重发
            ->whereIn('skin_record_id', $today_staff_same_wx_user_rec_ids)
            ->exists();

        return $exist;
    }

    /**
     * 对同一客户下的消费者，一天只有第一次成功测此消费者的店员可获取红包
     *
     * @param SkinRecord $skinRecord
     * @return bool
     */
    private function isWxUserSameCustomerBonusExistToday(SkinRecord $skinRecord): bool
    {
        $customer = $skinRecord->store->customer;
        $store_ids = $customer->getStoreIds();

        $today_same_customer_rec_ids = (new SkinRecord)
            ->filterToday('created_at')
            ->whereIn('store_id', $store_ids)
            ->where('wechat_user_id' , $skinRecord->wechat_user_id)
            ->pluck('id')
            ->all();

        $exist = $this->status['wx_same_customer_bonus_exist'] = (new SkinRecordBonus)
            ->where('bonus_status', SkinRecordBonus::BONUS_STATUS_SUCCESS) // 失败可重发
            ->whereIn('skin_record_id', $today_same_customer_rec_ids)
            ->exists();

        return $exist;
    }

    /**
     * @param SkinRecord $skinRecord
     *
     * @return bool
     */
    private function checkPayTypeHasRelateAccount(SkinRecord $skinRecord): bool
    {
        $use_ali = $this->status['use_ali_pay'] = $skinRecord->isBonusUseAliPay();
        if ($use_ali) {
            return $this->storeAdminHasAliAccount($skinRecord);
        } else {
            $this->status['use_wx_pay'] = true;
            
            return $this->storeAdminHasWechatUser($skinRecord);
        }
    }

    /**
     * @param SkinRecord $skinRecord
     *
     * @return bool
     */
    private function isAllSubSkinRecordsDone(SkinRecord $skinRecord): bool
    {
        $done = SkinRecordRepository::isAllSubSkinRecordsDone($skinRecord);

        $this->status['all_sub_records_done'] = $done;

        return $done;
    }

    private function isActivityAlive(): bool
    {
        /** @var Activity $act */
        $act = (new Activity)->find(Activity::ID_BONUS);
        if (! $act) {
            return $this->status['activity_alive'] = false;
        } else {
            $end_at = $act->ended_at;
            if (! $end_at) {
                return $this->status['activity_alive'] = true;
            } else {
                if (now() <= $end_at) {
                    return $this->status['activity_alive'] = true;
                } else {
                    return $this->status['activity_alive'] = false;
                }
            }
        }
    }
    
    private function storeAdminHasWechatUser(SkinRecord $skinRecord): bool
    {
        $this->status['staff_has_wx'] = (bool) ($skinRecord->storeAdmin->wechatUser ?? null);
        
        return $this->status['staff_has_wx'];
    }
    
    /**
     * @param SkinRecord $skinRecord
     * @return bool
     */
    private function storeAdminHasAliAccount(SkinRecord $skinRecord): bool
    {
        $acnt = $skinRecord->storeAdmin->ali_account ?? null;
        
        $has_acnt = $this->status['staff_has_ali_account'] = (bool) $acnt;
        
        return $has_acnt;
    }

    /**
     * 对应的账号（机器）可否发红包
     *
     * @param SkinRecord $skinRecord
     *
     * @return bool
     */
    private function canAccountGrant(SkinRecord $skinRecord): bool
    {
        $can = ! in_array($skinRecord->device_account_id, self::DISABLE_GRANT_DEV_ACNT_IDS);

        return $this->status['account_can_grant'] = $can;
    }
}
